/******************************************************************************
 * Copyright (C) 2025 COMPANY or its affiliates.
 *
 * All Rights Reserved.
 *
 @file ota.c
 *
 @par dependencies
 - ota.h  // 对应头文件
 *
 @author liubin | R&D Dept. | COMPANY
 *
 @brief 模块核心功能实现，包括：
            - 功能点1：xxx初始化与配置
            - 功能点2：xxx数据处理与交互
            - 功能点3：xxx资源管理与释放
 *
 Processing flow:
 * 1. 初始化阶段：
            - 调用xxx_init()完成硬件/软件初始化
            - 初始化全局变量与静态变量
            - 注册回调函数（如需要）
 * 2. 运行阶段：
            - 接收输入数据（如xxx_rx()）
            - 调用核心处理函数（如xxx_process()）
            - 输出处理结果（如xxx_tx()）
 * 3. 销毁阶段：
            - 调用xxx_deinit()释放资源
            - 重置变量状态（如需要）
 *
 @version V1.0 2025-11-01
 *
 @note 1 tab == 4 spaces!
 *       - 实现说明：如使用DMA传输、中断优先级配置
 *       - 性能限制：如最大处理速率、内存占用上限
 *       - 调试提示：关键日志输出位置、断点设置建议
 *
 *****************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "ota.h"
#include "elog.h"
#include "usart.h"
#include "ymodem.h"

#include "w25qxx_handler.h"
#include "system.h"
#include "SEGGER_RTT.h"
/* Private typedef -----------------------------------------------------------*/
#define TAG "ota"

QueueHandle_t Q_YmodemReclength; /* 用于接收 Ymodem 数据长度的队列 */

osThreadId_t OTA_taskHandle;
const osThreadAttr_t OTA_task_attributes = {
    .name = "OTA_task",
    .stack_size = 512 * 4,
    .priority = (osPriority_t)osPriorityAboveNormal1,
};

QueueHandle_t Q_AppBuffer;        /* 用于接收应用数据buff地址的队列 */
xSemaphoreHandle S_ExtFlashState; /* 用于保护外部Flash状态的信号量 */

osThreadId_t DownloadAppData_taskHandle;
const osThreadAttr_t DownloadAppData_task_attributes = {
    .name = "DownloadAppData_task",
    .stack_size = 512 * 4,
    .priority = (osPriority_t)osPriorityAboveNormal1,
};

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
// uint8_t g_au8_YmodemRec[1030];

uint8_t g_u8_YmodemRec_A[1030]; // 双缓冲区 A
uint8_t g_u8_YmodemRec_B[1030]; // 双缓冲区 B

static E_OTA_STATUS s_e_Ota_Status = OTA_STATUS_WAIT_DOWNLOAD;
static uint8_t s_u8_OtaCmd[4];
/* Global variables ----------------------------------------------------------*/
extern QueueHandle_t key_queue;
/* Private function prototypes -----------------------------------------------*/

/* Global function prototypes -------------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
void download_appdata_task(void* argument);
/* Global functions ----------------------------------------------------------*/

void SoftReset(void)
{
  __set_FAULTMASK(1); // 关闭所有可屏蔽的硬件异常 cotex-m 内核寄存器

  NVIC_SystemReset();
}

void ota_task_runnable(void* argument)
{
  /* USER CODE BEGIN key_task_runnable */
  uint8_t rec_length = 0;
  uint8_t t_u8_AckCmd[] = {0x44, 0x55, 0x66};
  uint8_t e;          // 按键事件
  TickType_t ticks;   // 时间
  uint32_t t_tic = 0; // 临时变量
  int32_t t_int32_YmodemRecLength;
  /* Infinite loop */
  for (;;)
  {

    switch (s_e_Ota_Status)
    {
    case OTA_STATUS_WAIT_DOWNLOAD:
    elog_i(TAG, "OTA_STATUS_WAIT_DOWNLOAD");
      /* 1.阻塞接收命令 */
      HAL_UARTEx_ReceiveToIdle_DMA(&huart1, s_u8_OtaCmd, 4);
      /* 2.等待数据接收完成 */
      xQueueReceive(Q_YmodemReclength, &rec_length, portMAX_DELAY);

      /* 3.校验数据长度*/
      //if (rec_length == 3)
      {
        /* 4.校验数据内容*/
        if (0x11 == s_u8_OtaCmd[0] && 0x22 == s_u8_OtaCmd[1] && 0x33 == s_u8_OtaCmd[2]) // 下载命令
        {
          /* 5.校验通过 切换状态*/
          s_e_Ota_Status = OTA_STATUS_DOWNLOAD;
          /* 6.创建下载任务 把app数据下载到外部flash 中*/
          DownloadAppData_taskHandle =
              osThreadNew(download_appdata_task, NULL, &DownloadAppData_task_attributes);
          Q_AppBuffer = xQueueCreate(2, sizeof(uint8_t*));
          S_ExtFlashState = xSemaphoreCreateMutex(); 

          elog_i(TAG, "GO TO OTA_STATUS_DOWNLOAD");
        }
        else
        {
          memset(s_u8_OtaCmd, 0, 4);
        }
      }
//      else
//      {
//        memset(s_u8_OtaCmd, 0, 4);
//      }

      break;
    case OTA_STATUS_DOWNLOAD:
			t_int32_YmodemRecLength = Ymodem_Receive(g_u8_YmodemRec_A,g_u8_YmodemRec_B);
      if (t_int32_YmodemRecLength > 0)
      {
        s_e_Ota_Status = OTA_STATUS_WAIT_UPDATE;
        HAL_UART_Transmit(&huart1, t_u8_AckCmd, 3, 100);

        xSemaphoreTake(S_ExtFlashState,portMAX_DELAY);
        W25Q64_WriteDataEnd();
        xSemaphoreGive(S_ExtFlashState);

         // 更新系统配置
        // system_config_set_app_status(APP_UPDATE_STATUS_DOWNLOADING);
        // system_config_set_current_app_size(t_int32_YmodemRecLength); // 需要实现获取当前APP大小的函数
        elog_i(TAG, "GO TO OTA_STATUS_WAIT_UPDATE");
      }
      else
      {
    
        s_e_Ota_Status = OTA_STATUS_WAIT_DOWNLOAD;
        elog_e(TAG, "GO TO OTA_STATUS_WAIT_DOWNLOAD [%d]",t_int32_YmodemRecLength);
        SEGGER_RTT_printf(0,"%s,LINE:%d,%d err code \n",TAG,__LINE__,t_int32_YmodemRecLength);
      }  
      /* 清除 资源*/
      vQueueDelete(Q_AppBuffer);
      vTaskDelete(DownloadAppData_taskHandle);
      vSemaphoreDelete(S_ExtFlashState);
      break;
    case OTA_STATUS_WAIT_UPDATE:
      /* 1.阻塞接收命令 */
      HAL_UARTEx_ReceiveToIdle_DMA(&huart1, s_u8_OtaCmd, 4);
      /* 2.等待数据接收完成 */
      xQueueReceive(Q_YmodemReclength, &rec_length, portMAX_DELAY);
      // for(int i=0;i<rec_length;i++)
      // {
      // 	HAL_UART_Transmit(&huart1,&s_u8_OtaCmd[i],1,10);
      // }
      /* 3.校验数据长度*/
      if (rec_length == 3)
      {
        /* 4.校验数据内容*/
        if (0x77 == s_u8_OtaCmd[0] && 0x88 == s_u8_OtaCmd[1] && 0x99 == s_u8_OtaCmd[2]) // 升级命令
        {
          s_e_Ota_Status = OTA_STATUS_END;
          ticks = xTaskGetTickCount(); // 获取当前时间
          // system_config_set_app_status(APP_UPDATE_STATUS_REQUEST_UPDATE);
          elog_i(TAG, "go to OTA_STATUS_END");
        }
        else
        {
          memset(s_u8_OtaCmd, 0, 4);
        }
      }
      else
      {
        elog_e(TAG, "do not support");
        memset(s_u8_OtaCmd, 0, 4);
      }
      break;
    case OTA_STATUS_END:

      if (xTaskGetTickCount() - ticks < 20 * 1000) // 20s 以内
      {
        if (t_tic == 0)
        {
          elog_w(TAG, "Restart immediately?");
          elog_w(TAG, "是否立即重启?");
          t_tic += 1;
        }

        if (key_queue != NULL)
        {
          if (xQueueReceive(key_queue, &e, 100))
          {
            elog_i(TAG, "key.event [%d][RECEIVE]", e);
            elog_e(TAG, "SoftReset");
            SoftReset();
          }
        }
        vTaskDelay(10);
      }
      else
      {
        s_e_Ota_Status = OTA_STATUS_WAIT_DOWNLOAD;
        elog_i(TAG, "go to OTA_STATUS_WAIT_DOWNLOAD");
      }

      break;
    default:
      break;
    }
    // Ymodem_Receive(g_au8_YmodemRec);
  }
  /* USER CODE END key_task_runnable */
}

int32_t download_appdata_packet_length; //每个包的长度
extern int32_t packet_length;
void download_appdata_task(void* argument)
{
  /* USER CODE BEGIN download_appdata_task */
  uint8_t *p_u8_data = NULL;
  uint32_t *p_u32_size = NULL;
	
  /* ymodem 协议第一帧数据是文件名+数据大小 */
  //参考 https://blog.csdn.net/huangdenan/article/details/103611081
  xQueueReceive(Q_AppBuffer,&p_u32_size,portMAX_DELAY);
  // 擦除对应的外部flash 扇区
  SEGGER_RTT_printf(0,"[%d]%s,LINE:%d,%d\n",xTaskGetTickCount(),TAG,__LINE__,*p_u32_size);
  xSemaphoreGive(S_ExtFlashState);
  /* Infinite loop */
  for (;;)
  {
    xQueueReceive(Q_AppBuffer,&p_u8_data,portMAX_DELAY);
    xSemaphoreTake(S_ExtFlashState,portMAX_DELAY);
    if (p_u8_data==NULL)
    {
      continue;// 跳过
    }
//    elog_i(TAG, "write flash [%d]",packet_length);
		//SEGGER_RTT_printf(0,"[%d]%s,LINE:%d,%d\n",xTaskGetTickCount(),TAG,__LINE__,packet_length);
		SEGGER_RTT_printf(0,"%d\n",download_appdata_packet_length);
    // 写入外部flash
    W25Q64_WriteData(p_u8_data,(uint32_t)download_appdata_packet_length);
    xSemaphoreGive(S_ExtFlashState);// 释放信号量
  }
}
